﻿using System;
using System.IO;
using System.Net;
using AgNet.Helpers;
using AgNet.Models;
using Newtonsoft.Json;
using RestSharp;
using RestSharp.Deserializers;

namespace AgNet
{
    public partial class AgNetClient
    {
        /// <summary>
        /// Retrieve a AgSession object using the user's Audiogalaxy credentials (email and password). 
        /// Note that you MUST NOT store the user's email or password. 
        /// The AgSession can be stored and remains valid until the user revokes authorization for your application
        /// </summary>
        /// <param name="mail">the user's email address associated with their Audiogalaxy account</param>
        /// <param name="password">the user's password associated with their Audiogalaxy account</param>
        /// <returns>the session information object to store</returns>
        public AgSession Login(string mail, string password)
        {
            var request = this.requestHelper.CreateLoginRequest(this.clientId, this.appSecret, mail, password);

            return this.Execute<AgSession>(request);
        }

        /// <summary>
        /// When your session expires, the API endpoints will respond with HTTP 401
        /// Unauthorized, per the requirement of the OAuth 2.0 spec. 
        /// At any time, you can use the token endpoint with your refresh token 
        /// to get a new session token
        /// </summary>
        /// <param name="previousSession">The session containing the refresh token</param>
        /// <returns>The new session object</returns>
        public AgSession RefreshSession(AgSession previousSession)
        {
            var request = this.requestHelper.CreateLoginRequest(this.clientId, this.appSecret, previousSession.RefreshToken);

            return this.Execute<AgSession>(request);
        }

        public AgUserInfo FetchUserInfo(AgSession session)
        {
            var request = this.requestHelper.CreateUserInfoRequest(this.clientId, session.AccessToken);

            return this.Execute<AgUserInfo>(request);
        }

        /// <summary>
        /// Fetch the list of users's playlists, artists, albums or genres.
        /// </summary>
        /// <param name="type">The type of resource (playlists|artists|genres).</param>
        /// <param name="offset">0-based offset to begin retrieving from.</param>
        /// <param name="imgSize">Small, medium or large size image.</param>
        /// <returns>The list of resources of requested type.</returns>
        public AgResourcesList FetchResourceList(ResourceTypes type, int offset, ImageSizes imgSize, AgSession session)
        {
            var request = this.requestHelper.FetchResourceListRequest(type, offset, imgSize, this.clientId, session.AccessToken);

            return this.Execute<AgResourcesList>(request);
        }

        /// <summary>
        /// Fetch the list of songs by playlist, artist, genre.
        /// </summary>
        /// <remarks>NOTE: Album is handled slightly differently</remarks>
        /// <param name="type">The type of resource to look into (playlist|artist|genre).</param>
        /// <param name="resourceId">The id of the resource you wish to fetch.</param>
        /// <param name="offset">0-based offset to begin retrieving from .</param>
        /// <returns></returns>
        public AgSongsList FetchSongList(ResourceTypes type, string resourceId, int offset, AgSession session)
        {
            var request = this.requestHelper.FetchSongsListRequest(type, resourceId, offset, this.clientId, session.AccessToken);

            return this.Execute<AgSongsList>(request);
        }

        public Stream FetchAudio(string audioToken, AgSession session)
        {
            var request = this.requestHelper.FetchAudio(audioToken, "ogg", "low", "live_stream", this.clientId, session.AccessToken);

            Uri uri = this.restClient.BuildUri(request);

            HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);

            HttpWebResponse response = (HttpWebResponse)httpWebRequest.GetResponse();

            Stream audioStream = response.GetResponseStream();

            return audioStream;
        }

        public T Execute<T>(RestRequest request) where T : new()
        {
            var response = this.restClient.Execute<T>(request);

            if (response.ResponseStatus != ResponseStatus.Completed)
            {
                // TODO: throw a communication error
            }

            var error = JsonConvert.DeserializeObject<Models.AgError>(response.Content);
            if (error.Message != null)
            {
                throw new AgNet.Exceptions.AgException(error.Message, error.Error);
            }

            return response.Data;
        }
    }
}
